#ifndef __UTILS_H__
#define __UTILS_H__

#include <ntifs.h>

// string helpers
NTSTATUS AllocateUnicodeString(OUT PUNICODE_STRING pUnicodeString,
                               IN const unsigned short ulLength,
                               IN const POOL_TYPE poolType);

void FreeUnicodeString(OUT PUNICODE_STRING pUnicodeString);

// call FreeUnicodeString for pusDestination if it no longer need
NTSTATUS ConcatUnicodeString(IN const PUNICODE_STRING pusFirst,
                             IN const PUNICODE_STRING pusSecond,
                             OUT PUNICODE_STRING pusDestination,
                             IN const POOL_TYPE poolType);

// call FreeUnicodeString for free pusObjectName 
NTSTATUS GetObjectName(IN PVOID pObject,
                       OUT PUNICODE_STRING pusObjectName,
                       IN const POOL_TYPE poolType);

// IRP processing helpers
void SetStatusIRP(IN OUT PIRP pIRP, IN const NTSTATUS ntStatus, IN const ULONG_PTR ulpInformation);

NTSTATUS CompleteIRP(PIRP pIRP,
                     CCHAR ccPriorityBoost);

NTSTATUS SetStatusAndCompleteIRP(PIRP pIRP,
                                 const NTSTATUS ntStatus,
                                 const ULONG_PTR ulpInformation,
                                 CCHAR ccPriorityBoost);

NTSTATUS PassThroughIRP(PIRP pIRP, PDEVICE_OBJECT pNextLowerDevice);

// forwards the IRP down and wait, returns STATUS_UNSUCCESSFULL if no more device stacks
NTSTATUS WaitForIRPCompletion(IN PDEVICE_OBJECT pNextLowerDevice, IN PIRP pIRP);

// FS helpers
typedef void(*PVOLUMEENUMERATOR)(IN PDEVICE_OBJECT pVolumeDeviceObject, IN PVOID pContext);

// enumerates volumes and using PVOLUMEENUMERATOR as callback
NTSTATUS EnumerateFSVolumes(IN PDEVICE_OBJECT pTargetCDO, IN PVOLUMEENUMERATOR pCallback, IN PVOID pContext);

// ----- registry helpers -----

// pointer to function processing registry values (calls for any MULTI_SZ item)
typedef NTSTATUS (*PENUMERATE_CALLBACK)(const PUNICODE_STRING pusVal,
                                    const wchar_t* pwsMultiSZItem);

// getting values from registry
NTSTATUS EnumerateMultiSZValue(const PUNICODE_STRING pusKey,
                               const PUNICODE_STRING pusValue,
                               PENUMERATE_CALLBACK pCallback);

// ----------------------------

// ----- resource helpers -----

NTSTATUS AcquireResource(IN PERESOURCE pResource, IN const BOOLEAN bExclusive);
NTSTATUS ReleaseResource(IN PERESOURCE pResource);

// ----------------------------
#endif